package com.remote.ui.component;


import com.remote.common.command.Commands;
import com.remote.common.constant.Constants;
import com.remote.common.exception.RemoteException;
import com.remote.common.model.Request;
import com.remote.common.model.Response;
import com.remote.common.model.fx.MasterKeyEvent;
import com.remote.common.model.fx.MasterMouseEvent;
import com.remote.common.tool.MachineTool;
import com.remote.common.util.TaskExecutors;
import com.remote.common.util.Utils;
import com.remote.ui.core.BaseControllerComponent;
import com.remote.ui.core.ControllerManager;
import io.netty.channel.ChannelHandlerContext;

import java.awt.event.KeyEvent;


/**
 * @author Cool-Coding
 * 2018/7/25
 */
public class ScreenComponent extends BaseControllerComponent {
    private ControllerManager controllerManager;
    private Integer quality;
    private MachineTool machineTool;

    public ScreenComponent() {
        //默认清晰度
        this.quality = Constants.SCREEN_QUALITY;
        this.machineTool = MachineTool.getInstance();
    }

    @Override
    protected void onRead0(ChannelHandlerContext ctx, Response response) {
        try {
            switch ((Commands) response.getCommand()) {
                case CONTROL:
                    String clientId = getControllerManager().getCommandContext().getClient().getClientId();
                    if (clientId.equals(response.getTargetClientId())) {
                        TaskExecutors.submit(new ScreenshotsTask(), 0, 1000 / 60);
                    }
                    break;
                case QUALITY:
                    quality = (Integer) response.getValue();
                    break;
                case KEYBOARD:
                    MasterKeyEvent keyEvent = (MasterKeyEvent) response.getValue();
                    if (keyEvent.isPressed()) {
                        keyPress(keyEvent);
                        keyRelease(keyEvent);
                    } else {  //为了处理pressed之后的延迟，press后立即释放
                    }
                    break;
                case MOUSE:
                    MasterMouseEvent mouseEvent = (MasterMouseEvent) response.getValue();
                    mouse(mouseEvent);
                    break;
                default:
                    break;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }


    private void mouse(MasterMouseEvent mouseEvent) {
        if (mouseEvent.isClicked()) {
            final int mouseButton1 = mouseEvent.getJWTMousea();
            machineTool.getRobot().mousePress(mouseButton1);
            machineTool.getRobot().mouseRelease(mouseButton1);
        }
        if (mouseEvent.isDoubleClicked()) {
            final int mouseButton1 = mouseEvent.getJWTMousea();
            machineTool.getRobot().mousePress(mouseButton1);
            machineTool.getRobot().mouseRelease(mouseButton1);
            machineTool.getRobot().mousePress(mouseButton1);
            machineTool.getRobot().mouseRelease(mouseButton1);
        }
        if (mouseEvent.isDragged()) {
            final int mouseButton1 = mouseEvent.getJWTMousea();
            machineTool.getRobot().mousePress(mouseButton1);
            machineTool.getRobot().mouseMove((int) mouseEvent.getX(), (int) mouseEvent.getY());
        }
        if (mouseEvent.isMouseMoved()) {
            machineTool.getRobot().mouseMove((int) mouseEvent.getX(), (int) mouseEvent.getY());
        }
        if (mouseEvent.isMouseWheel()) {
            machineTool.getRobot().mouseWheel(mouseEvent.getMouseWheel());
        }
        if (mouseEvent.isMousePressed()) {
            final int mouseButton1 = mouseEvent.getJWTMousea();
            machineTool.getRobot().mousePress(mouseButton1);
            //同键盘按键一样，为了处理按下之后的延迟，按下后即释放
            machineTool.getRobot().mouseRelease(mouseButton1);
        }
        if (mouseEvent.isMouseReleased()) {
            final int mouseButton1 = mouseEvent.getJWTMousea();
            machineTool.getRobot().mouseRelease(mouseButton1);
        }
    }


    /**
     * 键按下
     *
     * @param keyEvent
     */
    private void keyPress(MasterKeyEvent keyEvent) {
        if (keyEvent.isAltDown()) {
            machineTool.getRobot().keyPress(KeyEvent.VK_ALT);
        }
        if (keyEvent.isCtrlDown()) {
            machineTool.getRobot().keyPress(KeyEvent.VK_CONTROL);
        }
        if (keyEvent.isShiftDown()) {
            machineTool.getRobot().keyPress(KeyEvent.VK_SHIFT);
        }
        machineTool.getRobot().keyPress(keyEvent.getKeyCode());
    }

    /**
     * 键释放
     *
     * @param keyEvent
     */
    public void keyRelease(MasterKeyEvent keyEvent) {
        if (keyEvent.isAltDown()) {
            machineTool.getRobot().keyRelease(KeyEvent.VK_ALT);
        }
        if (keyEvent.isCtrlDown()) {
            machineTool.getRobot().keyRelease(KeyEvent.VK_CONTROL);
        }
        if (keyEvent.isShiftDown()) {
            machineTool.getRobot().keyRelease(KeyEvent.VK_SHIFT);
        }
        machineTool.getRobot().keyRelease(keyEvent.getKeyCode());
    }


    public class ScreenshotsTask implements Runnable {
        //上一个截屏
        private byte[] previousScreen;

        private String taskName;

        @Override
        public void run() {
            try {
                final byte[] now = ScreenComponent.this.machineTool.getScreenSnapshot(quality);
                final String currentClientId = getControllerManager().getCommandContext().getClient().getClientId();
                if (isDifferentFrom(now)) {//与上一个屏幕相同就发送心跳
                    final Request request = Utils.buildRequest(currentClientId, Commands.SCREEN, now);
                    getControllerManager().getCommandContext().fireCommand(request);
                } else {
//                    Request request = Utils.buildRequest(currentClientId, Commands.HEARTBEAT, null);
//                    getControllerManager().getCommandContext().fireCommand(request);
                }
            } catch (Exception e) {
                throw new RemoteException(e);
            }
        }


        /**
         * 比较上一个屏幕与当前屏幕是否一样
         *
         * @param now
         * @return
         */
        private boolean isDifferentFrom(byte[] now) {
            byte[] previousScreen = getPreviousScreen();
            if (now == null) {
                return false;
            }
            // 如果前一个屏幕为空，而且当前屏幕与前一个屏幕不一样，则发送
            if (previousScreen == null || previousScreen.length == 0 || previousScreen.length != now.length) {
                setPreviousScreen(now);
                return true;
            }
            int len = previousScreen.length;
            boolean changeable = false;
            for (int i = 0; i < len; i++) {
                if (previousScreen[i] != now[i]) {
                    setPreviousScreen(now);
                    changeable = true;
                    break;
                }
            }
            return changeable;
        }

        protected byte[] getPreviousScreen() {
            return previousScreen;
        }

        protected void setPreviousScreen(byte[] previousScreen) {
            this.previousScreen = previousScreen;
        }

    }


}
